﻿using System;
using System.Drawing.Drawing2D;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Runtime.InteropServices.ComTypes;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Threading;
using System.Windows.Forms;
using IDataObject = System.Runtime.InteropServices.ComTypes.IDataObject;

namespace FicusFactor.Watermarker
{
    [Guid("4A4717A7-FCB9-4A4D-A23C-C3A85D1C6913")]
    [ComVisible(true)]
    public sealed class Watermarker : WatermarkerBase
    {
        private ConfiguratorForm configuratorUI;
        private static readonly object Synchronizer = new object();
        //private static WatermarkStatusWindow status = new WatermarkStatusWindow();

        public override void Drop(IDataObject dataObject, uint keyState, Point pt, ref uint effect)
        {
            base.Drop(dataObject, keyState, pt, ref effect);

            if (null == configuratorUI)
            {
                configuratorUI = new ConfiguratorForm();
            }

            if (true == configuratorUI.DefaultSettings)
            {
                configuratorUI.ShowDialog();
            }

            /*
            lock (Synchronizer)
            {
                if (status.IsDisposed == true)
                {
                    status = new WatermarkStatusWindow();
                }

                if (status.Visible == false)
                {
                    status.Show();
                }

                status.Clear();
            }
            */

            for (int i = 0; i < Files.Count; i++)
            {
                DialogResult dr = WatermarkImage(Files[i]);

                if (dr == DialogResult.Retry)
                {
                    i--;
                }
                else if (dr == DialogResult.Abort || dr == DialogResult.Cancel)
                {
                    return;
                }
            }

            //status.Close();
        }

        internal static DialogResult WatermarkImage(string imageFile)
        {
            Settings settings = Settings.Load();

            try
            {
                using (Image i = ApplyWatermark(settings, imageFile))
                {
                    string outputImageFile = Path.GetFileNameWithoutExtension(imageFile);
                    string ext = Path.GetExtension(imageFile);
                    string outputFile = Path.Combine(settings.OutputFolder, outputImageFile + " - watermarked" + ext);
                    //status.WriteLogEntry("Applying watermark to image. Source: \"{0}\" Destination: \"{1}\"", imageFile, outputFile);
                    i.Save(outputFile);
                    //status.WriteLogEntryLine("... done!");
                }

                return DialogResult.OK;
            }
            catch (Exception e)
            {
                //status.WriteLogEntryLine("\r\nError applying watermark to source image \"{0}\": {1}: {2} {3}", imageFile, e.GetType(), e.Message, e.StackTrace);
                return MessageBox.Show(string.Format("{0} {1}: {2}", e.GetType(), e.Message, e.StackTrace), "Sorry, there was an error. :(", MessageBoxButtons.AbortRetryIgnore);
            }
        }

        internal static Image ApplyWatermark(Settings settings, string imageFile)
        {
            Image i = Image.FromFile(imageFile);
            Graphics g = Graphics.FromImage(i);
            Brush b = new SolidBrush(Color.FromArgb(settings.GetAlpha(), settings.ToColor()));
            Point p;
            Font f = null;

            try
            {
                if (settings.FontSizeIsProportional == false)
                {
                    f = settings.ToFont();
                }
                else
                {
                    // BUG: This is a hack and it doesn't quite work like I would want. My math skills suck too
                    // much to figure out a great formula for determining the best proportional font size based
                    // on the image size. This works well enough for now, though.
                    float proportionalFontSize = ((i.Width / g.DpiY) / settings.WatermarkText.Length) * 100;
                    f = new Font(settings.FontName, proportionalFontSize, settings.FontStyle, settings.GraphicsUnit);
                }

                SizeF sz = g.MeasureString(settings.WatermarkText, f);
                int x = (int)(i.Width - sz.Width) / 2;
                int y = 0;

                switch (settings.Position)
                {
                    case WatermarkPosition.Center:
                    case WatermarkPosition.Diagonal:
                        y = (int)(i.Height - sz.Height) / 2;
                        break;
                    case WatermarkPosition.Top:
                        y = 0;
                        break;
                    case WatermarkPosition.Bottom:
                        y = (int)(i.Height - sz.Height);
                        break;
                }

                if (settings.Position == WatermarkPosition.Diagonal)
                {
                    sz = g.VisibleClipBounds.Size;
                    g.TranslateTransform(sz.Width / 2, sz.Height / 2);
                    sz = g.MeasureString(settings.WatermarkText, f);

                    // BUG: If the image is really wide it will go off the page boundary
                    float rotation = -45;

                    /*
                    if (sz.Width < g.VisibleClipBounds.Width)
                    {
                        rotation = ((sz.Width / sz.Height) * 100) / -45;
                    }
                     */
                    g.RotateTransform(rotation);
                    p = new Point(-((int)sz.Width / 2), -((int)sz.Height / 2));
                }
                else
                {
                    p = new Point(x, y);
                }

                g.DrawString(settings.WatermarkText, f, b, p);
                g.ResetTransform();

                return i;
            }
            finally
            {
                if (g != null)
                {
                    g.Dispose();
                }

                if (f != null)
                {
                    f.Dispose();
                }

                if (b != null)
                {
                    b.Dispose();
                }
            }
        }

        #region IDisposable Members

        protected override void Dispose(bool disposing)
        {
            base.Dispose(disposing);

            if (true == disposing)
            {
                if (null != configuratorUI && configuratorUI.IsDisposed == false)
                {
                    configuratorUI.Dispose();
                }
            }
        }

        #endregion
    }
}